import java.util.*;

public class TicketSaleSystem {
	public static void main(String[] args) {
		TicketSaleSystem saleSystem = new TicketSaleSystem();
		while (true) try {
			saleSystem.showPurchaseResults();
			int result = saleSystem.produceTicket(false);
			switch (result) {
				case 0:
					System.exit(0);
				case 1:
					System.out.println("releasing new round");
					saleSystem.startAll();
			}
		} catch (Exception exception) {
			System.out.println(exception.getMessage());
		}
	}

	private LinkedList<Ticket> tickets;
	LinkedList<Buyer> buyers;
	LinkedList<Thread> purchases;
	private LinkedList<String> messages;
	Scanner scanner;
	int maxTicket,
			customer,
			released;

	TicketSaleSystem() {
		try {
			purchases = new LinkedList<>();
			tickets = new LinkedList<>();
			buyers = new LinkedList<>();
			messages = new LinkedList<>();
			scanner = new Scanner(System.in);
			maxTicket = 0;
			while (true) {
				System.out.println("max ticket:");
				maxTicket = scanner.nextInt();
				if (maxTicket > 0) break;
				System.out.println("ticket amount must be a positive number");
			}
			while (true) {
				System.out.println("customer:");
				customer = scanner.nextInt();
				if (customer > maxTicket) break;
				System.out.println("**too few customers to compete ");
			}
			for (int i = 0; i < customer; i++)
				buyers.add(new Buyer(i));
			released = 0;
		} catch (Exception e) {
			System.out.println("init: invalid input");
		}
		try {
			while (true) {
				switch (produceTicket(true)) {
					case 1:
						System.out.println("tickets generated");
						startAll();
						break;
					case 0:
						System.out.println("Welcome to use again");
						System.exit(0);
					default:
						continue;
				}
				break;
			}
		} catch (Exception e) {
			System.out.println("invalid input");
		}
	}

	void startAll() {
		purchases.clear();
		for (Buyer buyer : buyers) {
			if (buyer.ticket != null) continue;
			Thread purchase = new Thread(buyer);
			purchases.add(purchase);
			purchase.start();
		}
	}

	void addMessage(String msg) {
		messages.add(msg);
	}

	void showPurchaseResults() {
		while (true) {
			boolean allFinished = true;
			for (Thread purchase : purchases)
				if (purchase.isAlive()) {
					allFinished = false;
					break;
				}
			if (allFinished) break;
		}
		while (!messages.isEmpty())
			System.out.println(messages.removeFirst());
	}

	/**
	 * @param first whether this is the initial ticket release
	 * @return 1 if there are tickets generated successfully
	 * <p>
	 * 0 if choice to exit the system has been received from the interface
	 * <p>
	 * -1 if a negative number has been received from the console
	 */

	int produceTicket(boolean first) {
		if (first) System.out.println("release how many tickets first:");
		else System.out.println("how many to add*********************************************************");
		int toRelease = scanner.nextInt();
		if (toRelease == 0) {
			System.out.println("welcome to use again");
			return 0;
		}
		if (toRelease + released <= maxTicket) {
			for (int i = 0; i < toRelease; i++)
				tickets.add(new Ticket(released++));
			System.out.println("tickets generated");
			return 1;
		}
		System.out.println("**too many tickets released");
		return -1;
	}

	synchronized Ticket buy() {
		try {
			return tickets.removeFirst();
		} catch (Exception e) {
			return null;
		}
	}

	record Ticket(int seatNum) implements Comparator<Ticket> {

		@Override
			public String toString() {
				return String.valueOf(seatNum);
			}

			@Override
			public int compare(Ticket o1, Ticket o2) {
				return Integer.compare(o1.seatNum, o2.seatNum);
			}

			@Override
			public boolean equals(Object obj) {
				return false;
			}
		}

	class Buyer implements Runnable {
		int id;
		public Ticket ticket;

		public Buyer(int id) {
			this.id = id;
			this.ticket = null;
		}

		@Override
		public void run() {
			ticket = buy();
			addMessage(this.toString());
		}

		@Override
		public String toString() {
			return "Buyer No." + id + (
					(ticket == null)
							? " have not yet got the ticket"
							: " got seat No. " + ticket.seatNum);
		}
	}
}